/*
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.ziq.zcamp.util.bitmap;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.media.ExifInterface;
import android.media.MediaMetadataRetriever;
import android.os.Build;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Pair;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.core.util.Pools;

import com.blankj.utilcode.util.StringUtils;
import com.ziq.zcamp.util.io.IOUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;


/**
 * This class contains utility method for Bitmap
 */
public final class BitmapUtil {
    private static final int DECODE_BUFFER_SIZE = 16 * 1024;
    private static final int POOL_SIZE = 12;
    private static final Pools.SynchronizedPool<ByteBuffer> DECODE_BUFFERS
            = new Pools.SynchronizedPool<>(POOL_SIZE);

    private static final int ALPHA_COLOR = Color.WHITE;

    /**
     * Bytes per pixel definitions
     */
    public static final int ALPHA_8_BYTES_PER_PIXEL = 1;
    public static final int ARGB_4444_BYTES_PER_PIXEL = 2;
    public static final int ARGB_8888_BYTES_PER_PIXEL = 4;
    public static final int RGB_565_BYTES_PER_PIXEL = 2;

    public static final float MAX_BITMAP_SIZE = 2048f;

    /**
     * @return size in bytes of the underlying bitmap
     */
    @SuppressLint("NewApi")
    public static int getSizeInBytes(@Nullable Bitmap bitmap) {
        if (bitmap == null) {
            return 0;
        }

        // There's a known issue in KitKat where getAllocationByteCount() can throw an NPE. This was
        // apparently fixed in MR1: http://bit.ly/1IvdRpd. So we do a version check here, and
        // catch any potential NPEs just to be safe.
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
            try {
                return bitmap.getAllocationByteCount();
            } catch (NullPointerException npe) {
                // Swallow exception and try fallbacks.
            }
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            return bitmap.getByteCount();
        }

        // Estimate for earlier platforms. Same code as getByteCount() for Honeycomb.
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    /**
     * Decodes only the bounds of an image and returns its width and height or null if the size can't
     * be determined
     *
     * @param bytes the input byte array of the image
     * @return dimensions of the image
     */
    public static @Nullable
    Pair<Integer, Integer> decodeDimensions(byte[] bytes) {
        // wrapping with ByteArrayInputStream is cheap and we don't have duplicate implementation
        return decodeDimensions(new ByteArrayInputStream(bytes));
    }

    /**
     * Decodes only the bounds of an image and returns its width and height or null if the size can't
     * be determined
     *
     * @param is the InputStream containing the image data
     * @return dimensions of the image
     */
    public static @Nullable
    Pair<Integer, Integer> decodeDimensions(InputStream is) {
        ByteBuffer byteBuffer = DECODE_BUFFERS.acquire();
        if (byteBuffer == null) {
            byteBuffer = ByteBuffer.allocate(DECODE_BUFFER_SIZE);
        }
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        try {
            options.inTempStorage = byteBuffer.array();
            BitmapFactory.decodeStream(is, null, options);
            return (options.outWidth == -1 || options.outHeight == -1) ?
                    null : Pair.create(options.outWidth, options.outHeight);
        } finally {
            DECODE_BUFFERS.release(byteBuffer);
        }
    }

    /**
     * Returns the amount of bytes used by a pixel in a specific
     * {@link Bitmap.Config}
     *
     * @param bitmapConfig the {@link Bitmap.Config} for which the size in byte
     *                     will be returned
     * @return
     */
    public static int getPixelSizeForBitmapConfig(Bitmap.Config bitmapConfig) {

        switch (bitmapConfig) {
            case ARGB_8888:
                return ARGB_8888_BYTES_PER_PIXEL;
            case ALPHA_8:
                return ALPHA_8_BYTES_PER_PIXEL;
            case ARGB_4444:
                return ARGB_4444_BYTES_PER_PIXEL;
            case RGB_565:
                return RGB_565_BYTES_PER_PIXEL;
        }
        throw new UnsupportedOperationException("The provided Bitmap.Config is not supported");
    }

    /**
     * Returns the size in byte of an image with specific size
     * and {@link Bitmap.Config}
     *
     * @param width        the width of the image
     * @param height       the height of the image
     * @param bitmapConfig the {@link Bitmap.Config} for which the size in byte
     *                     will be returned
     * @return
     */
    public static int getSizeInByteForBitmap(int width, int height, Bitmap.Config bitmapConfig) {
        return width * height * getPixelSizeForBitmapConfig(bitmapConfig);
    }

    /**
     * 旋转Bitmap
     */
    public static Bitmap getRotateBitmap(Bitmap b, float rotateDegree) {
        Matrix matrix = new Matrix();
        matrix.postRotate(rotateDegree);
        Bitmap rotaBitmap = null;
        try {
            rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, false);
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutOfMemoryError error) {
            error.printStackTrace();
        }
        return rotaBitmap;
    }

    public static int getPicRotate(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 通过需要的宽高计算图片收缩的比例
     * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding bitmaps using the
     * decode* methods from {@link BitmapFactory}. This implementation calculates the closest inSampleSize that will
     * result in the final decoded bitmap having a width and height equal to or larger than the requested width and
     * height. This implementation does not ensure a power of 2 is returned for inSampleSize which can be faster when
     * decoding but results in a larger bitmap which isn't as useful for caching purposes.
     *
     * @param options   An options object with out* params already populated (run through a decode* method with
     *                  inJustDecodeBounds==true
     * @param reqWidth  The requested width of the resulting bitmap
     * @param reqHeight The requested height of the resulting bitmap
     * @return The value to be used for inSampleSize
     */
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (reqHeight <= 0 || reqWidth <= 0) {
            return inSampleSize;
        }

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float) height / (float) reqHeight);
            } else {
                inSampleSize = Math.round((float) width / (float) reqWidth);
            }

            //             This offers some additional logic in case the image has a strange
            //             aspect ratio. For example, a panorama may have a much larger
            //             width than height. In these cases the total pixels might still
            //             end up being too large to fit comfortably in memory, so we should
            //             be more aggressive with sample downloadPlayVideo the image (=largerinSampleSize).

            final float totalPixels = width * height;

            // Anything more than 2x the requested pixels we'll sample downloadPlayVideo
            // further.
            final float totalReqPixelsCap = reqWidth * reqHeight * 2;

            while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
                inSampleSize++;
            }
        }
        return inSampleSize;
    }

    /**
     * 通过一种比较省内存的方式获得bitmap
     */
    public static Bitmap getBitmap(Context context, int resId) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        // 获取资源图片
        InputStream is = null;
        Bitmap bitmap = null;
        try {
            is = context.getResources().openRawResource(resId);
            bitmap = BitmapFactory.decodeStream(is, null, opt);
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }

    public static BitmapDrawable getBitmapDrawableResized(Context context, int resId, int width, int height) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        // 获取资源图片
        InputStream is = null;
        Bitmap bitmap = null;
        try {
            is = context.getResources().openRawResource(resId);
            bitmap = BitmapFactory.decodeStream(is, null, opt);
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return new BitmapDrawable(context.getResources(), getResizedBitmap(bitmap, width, height));
    }

    /**
     * 根据resourceId获取缩略好的bitmap
     */
    public static Bitmap getBitmapResized(Context context, int resId, int width, int height) {
        return getBitmapDrawableResized(context, resId, width, height).getBitmap();
    }

    public static Bitmap getResizedBitmap(Bitmap bitmap, int width, int height) {
        Matrix matrix = new Matrix();
        matrix.postScale((float) width / (float) bitmap.getWidth(), (float) height / (float) bitmap.getHeight()); //长和宽放大缩小的比例

        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    /**
     * 获取缩放后的bitmap
     *
     * @param scale 缩放比例
     */
    public static Bitmap getScaledBitmap(Bitmap bitmap, float scale) {
        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale); //长和宽放大缩小的比例

        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    /**
     * 从本地获取bitmap
     */
    public static Bitmap getBitmapFromDisk(String fileName) {
        if (TextUtils.isEmpty(fileName)) {
            return null;
        }
        return getBitmapFromDisk(new File(fileName));
    }

    /**
     * 从本地获取bitmap
     */
    public static Bitmap getBitmapFromDisk(File file) {
        FileInputStream fis = null;
        Bitmap bitmap = null;
        try {
            if (file.exists()) {
                fis = new FileInputStream(file);
                bitmap = BitmapFactory.decodeStream(fis);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (OutOfMemoryError error) {//这里是有可能内存溢出的
            error.printStackTrace();
            return null;
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }

    public static Bitmap getBitmapFromDisk(String fileName, int reqWidth, int reqHeight) {
        if (TextUtils.isEmpty(fileName)) {
            return null;
        }
        return getBitmapFromDisk(new File(fileName), reqWidth, reqHeight);
    }

    public static Bitmap getBitmapFromDisk(File file, int reqWidth, int reqHeight) {
        Bitmap bitmap = null;
        try {
            if (file.exists()) {
                String absolutePath = file.getAbsolutePath();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeFile(absolutePath, options);
                options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
                options.inJustDecodeBounds = false;
                bitmap = BitmapFactory.decodeFile(absolutePath, options);
            }
        } catch (OutOfMemoryError error) {//这里是有可能内存溢出的
            error.printStackTrace();
            return null;
        }
        return bitmap;
    }

    /**
     * 将bitmap缓存到本地
     */
    public static void saveBitmapToDisk(String fileName, Bitmap bitmap) {
        if (!isBitmapAvailable(bitmap)) {
            return;
        }
        if (TextUtils.isEmpty(fileName)) {
            return;
        }
        saveBitmapToDisk(new File(fileName), bitmap);
    }

    /**
     * 将bitmap缓存到本地 JPEG格式
     */
    public static void saveBitmapToDiskJPEG(String fileName, Bitmap bitmap) {
        if (!isBitmapAvailable(bitmap)) {
            return;
        }
        if (TextUtils.isEmpty(fileName)) {
            return;
        }
        saveBitmapToDiskJPEG(new File(fileName), bitmap);
    }

    public static synchronized void saveBitmapToDisk(File file, Bitmap bitmap, boolean deleteFileIfExist) {
        if (!isBitmapAvailable(bitmap)) {
            return;
        }
        if (deleteFileIfExist && file.exists()) {
            deleteFile(file);
        }
        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            deleteFile(file);
        } catch (IOException e) {
            e.printStackTrace();
            deleteFile(file);
        } catch (Exception e) {
            e.printStackTrace();
            deleteFile(file);
        } catch (Throwable e) {
            e.printStackTrace();
            deleteFile(file);
        }
    }

    /**
     * 将bitmap缓存到本地
     */
    public static synchronized void saveBitmapToDisk(File file, Bitmap bitmap) {
        saveBitmapToDisk(file, bitmap, true);
    }

    /**
     * 将bitmap缓存到本地
     */
    private static void saveBitmapToDiskJPEG(File file, Bitmap bitmap) {
        if (!isBitmapAvailable(bitmap)) {
            return;
        }
        if (file.exists()) {
            deleteFile(file);
        }
        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            deleteFile(file);
        } catch (IOException e) {
            e.printStackTrace();
            deleteFile(file);
        } catch (Exception e) {
            e.printStackTrace();
            deleteFile(file);
        } catch (Throwable e) {
            e.printStackTrace();
            deleteFile(file);
        }
    }

    private static void deleteFile(File file) {
        file.delete();
    }

    /**
     * 判断bitmap是否可用 不能为空 不能是已经被回收的 isRecycled返回false
     */
    public static boolean isBitmapAvailable(Bitmap bitmap) {
        if (null == bitmap || bitmap.isRecycled()) {// 如果为null或者是已经回收了的就证明是不可用的
            return false;
        }
        return true;
    }

    /**
     * 私信发送图片尺寸压缩(如果图片小于100k或者尺寸在指定尺寸之内则不再压缩）
     */
    public static void compressPictureAndUpRight(String srcPath, String newPath) {
        long time = System.currentTimeMillis();

        int degree = ExifReader.readPictureDegree(srcPath);

        String compPath = degree == 0 ? newPath : newPath + "_cmp";
        compressBitmap(srcPath, compPath);
        if (degree == 0) {
            return;
        }

        //部分机型需要旋转图片
        time = System.currentTimeMillis();
        Bitmap origin = getBitmapFromDisk(compPath);
        Bitmap rotate = getRotateBitmap(origin, degree);
        if (origin != null) {
            origin.recycle();
        }
        boolean sucess = false;
        if (rotate != null) {
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(newPath);
                rotate.compress(Bitmap.CompressFormat.JPEG, 90, fos);
                sucess = true;
                new File(compPath).delete();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                rotate.recycle();
                IOUtils.close(fos);
            }
            rotate.recycle();
        }
        if (!sucess) {
            renameFile(compPath, newPath);
        }
    }

    public static int[] getImageWidthHeight(String path) {
        BitmapFactory.Options options = new BitmapFactory.Options();

        /**
         * 最关键在此，把options.inJustDecodeBounds = true;
         * 这里再decodeFile()，返回的bitmap为空，但此时调用options.outHeight时，已经包含了图片的高了
         */
        options.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(path, options); // 此时返回的bitmap为null
        /**
         *options.outHeight为原始图片的高
         */
        return new int[]{options.outWidth, options.outHeight};
    }

    public static void compressBitmap(String srcPath, String desPath) {
        long fileSize = getFileSize(srcPath);
        if (fileSize <= 1024 * 100) {
            copyFile(srcPath, desPath);
            return;
        }

        int[] size = getImageWidthHeight(srcPath);

        final int finalHeight = 1920;
        final int finalWidth = 1080;
        final int minHeight = 960;
        final int minWidth = 540;

        // 缩放图片的尺寸
        float w = size[0];
        float h = size[1];
        float hh = h < finalHeight ? h : finalHeight;//
        float ww = w < finalWidth ? w : finalWidth;//

        int picRotate = getPicRotate(srcPath);
        if (picRotate == 90 || picRotate == 270) {
            hh = finalWidth;
            ww = finalHeight;
        }
        // 最长宽度或高度1024
        float be = 1.0f;
        if (w / h > 2 || h / w > 2) {
            if (w / h > 2 && h > minHeight) {
                be = h / minHeight;
            } else if (w > minWidth) {
                be = w / minWidth;
            }
        } else {
            if (w > h && w > ww) {
                be = w / ww;
            } else if (w < h && h > hh) {
                be = h / hh;
            }
        }

        if (be <= 0) {
            be = 1.0f;
        }
        if (be <= 1.0) {
            copyFile(srcPath, desPath);
            return;
        }
        BitmapFactory.Options op = new BitmapFactory.Options();
        op.inJustDecodeBounds = false;
        op.inSampleSize = (int) be;// 设置缩放比例,这个数字越大,图片大小越小.
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, op);
        if (bitmap != null) {
            int desWidth = (int) (w / be);
            int desHeight = (int) (h / be);
            Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, desWidth, desHeight, true);
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(desPath);
                if (scaledBitmap != null) {
                    scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
                }
                return;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                bitmap.recycle();
                if (scaledBitmap != null) {
                    scaledBitmap.recycle();
                }
                IOUtils.close(fos);
            }
        }
        //有异常时
        copyFile(srcPath, desPath);
    }

    public static Bitmap decodeSampledBitmapFromFile(String filename, int reqWidth, int reqHeight) throws Throwable {
        // synchronized (lock1)
        {
            int sample = 0;
            try {
                // First decode with inJustDecodeBounds=true to check dimensions
                final BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeFile(filename, options);

                sample = calculateInSampleSize(options, reqWidth, reqHeight);
                // Calculate inSampleSize
                options.inSampleSize = sample;
                // Decode bitmap with inSampleSize set
                options.inJustDecodeBounds = false;
                // InKeLog.e("Image", "warn,path="+filename);
                return BitmapFactory.decodeFile(filename, options);
            } catch (Throwable e) {
                e.printStackTrace();
                if (e instanceof OutOfMemoryError) {
                    throw e;
                }
            }
        }
        return null;
    }

    public static byte[] bmpToByteArray(final Bitmap bmp) {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, 90, output);
        byte[] result = output.toByteArray();
        try {
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * @author WangChunliang
     * @Date 2015-7-14
     * @Description 图片加载回调
     */
    public interface BitmapLoadListener {
        void onBitmapLoaded(Bitmap bitmap);
    }

    /**
     * 水平镜像转换
     */
    public static Bitmap horizontalMirrorConvert(Bitmap bitmap) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        Bitmap newBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);// 创建一个新的和SRC长度宽度一样的位图
        Canvas canvas = new Canvas(newBitmap);
        Matrix matrix = new Matrix();
        //        m.postScale(1, -1); //镜像垂直翻转
        matrix.postScale(-1, 1); //镜像水平翻转
        //        m.postRotate(-90); //旋转-90度
        Bitmap tmpBitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
        canvas.drawBitmap(tmpBitmap, new Rect(0, 0, tmpBitmap.getWidth(), tmpBitmap.getHeight()), new Rect(0, 0, w, h),
                null);
        return newBitmap;
    }


    public static Bitmap convertViewToBitmap(View view) {
        if (null == view) {
            return null;
        }
        Bitmap bitmap = null;
        try {
            view.setDrawingCacheEnabled(true);
            view.buildDrawingCache(true);
            view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
            view.buildDrawingCache();
            bitmap = view.getDrawingCache(true);
        } catch (Exception e) {

        }
        if (null == bitmap) {
            return null;
        }
        return bitmap;
    }

    public static Bitmap mergeBitmap(Bitmap firstBitmap, Bitmap secendBitmap) {
        if (firstBitmap == null || secendBitmap == null) {
            return null;
        }
        Bitmap bitmap = Bitmap.createBitmap(firstBitmap.getWidth(), firstBitmap.getHeight(), firstBitmap.getConfig());
        Canvas canvas = new Canvas(bitmap);
        canvas.drawBitmap(firstBitmap, new Matrix(), null);
        canvas.drawBitmap(secendBitmap, 0, 0, null);
        return bitmap;
    }

    /**
     * 创建label的shape背景
     */
    public static Drawable createLabelBackground(String startColor, String endColor, int cornerValue) {
        int[] gradientColor = new int[2];
        try {
            gradientColor[0] = Color.parseColor("#" + startColor);
            gradientColor[1] = Color.parseColor("#" + endColor);
        } catch (Exception e) {
            gradientColor[0] = Color.parseColor("#04C7B7");
            gradientColor[1] = Color.parseColor("#06CAD6");
        }
        GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TL_BR, gradientColor);
        gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
        gradientDrawable.setCornerRadii(new float[]{0, 0, 0, 0, cornerValue, cornerValue, cornerValue, cornerValue});
        return gradientDrawable;
    }

    /**
     * 创建label的shape背景，支持边框和边框颜色
     */
    public static Drawable createLabelBackground(String startColor, String endColor, int cornerValue, int strokeWidthPx, int strokeColor) {
        int[] gradientColor = new int[2];
        try {
            gradientColor[0] = Color.parseColor(startColor);
            gradientColor[1] = Color.parseColor(endColor);
        } catch (Exception e) {
            gradientColor[0] = Color.parseColor("#04C7B7");
            gradientColor[1] = Color.parseColor("#06CAD6");
        }
        GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TL_BR, gradientColor);
        gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
        gradientDrawable.setStroke(strokeWidthPx, strokeColor);
        gradientDrawable.setCornerRadii(new float[]{cornerValue, cornerValue, cornerValue, cornerValue, cornerValue, cornerValue, cornerValue, cornerValue});
        return gradientDrawable;
    }

    /**
     * 创建label的shape背景,支持各个角弧度定制
     */
    public static Drawable createLabelBackground(String startColor, String endColor, int leftcornerValue, int topcornerValue, int rightcornerValue, int bottomcornerValue) {
        int[] gradientColor = new int[2];
        try {
            gradientColor[0] = Color.parseColor(startColor);
            gradientColor[1] = Color.parseColor(endColor);
        } catch (Exception e) {
            gradientColor[0] = Color.parseColor("#04C7B7");
            gradientColor[1] = Color.parseColor("#06CAD6");
        }
        GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TL_BR, gradientColor);
        gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
        gradientDrawable.setCornerRadii(new float[]{leftcornerValue, leftcornerValue, topcornerValue, topcornerValue,
                rightcornerValue, rightcornerValue, bottomcornerValue, bottomcornerValue});
        return gradientDrawable;
    }

    /**
     * 创建label的shape背景,支持各个角弧度定制,同时支持边框定制
     */
    public static Drawable createLabelBackground(String startColor, String endColor, int leftcornerValue, int topcornerValue, int rightcornerValue, int bottomcornerValue
            , int strokeWidthPx, int strokeColor) {
        int[] gradientColor = new int[2];
        try {
            gradientColor[0] = Color.parseColor(startColor);
            gradientColor[1] = Color.parseColor(endColor);
        } catch (Exception e) {
            gradientColor[0] = Color.parseColor("#04C7B7");
            gradientColor[1] = Color.parseColor("#06CAD6");
        }
        GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TL_BR, gradientColor);
        gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
        gradientDrawable.setCornerRadii(new float[]{leftcornerValue, leftcornerValue, topcornerValue, topcornerValue,
                rightcornerValue, rightcornerValue, bottomcornerValue, bottomcornerValue});
        gradientDrawable.setStroke(strokeWidthPx, strokeColor);
        return gradientDrawable;
    }

    /**
     * @param startColor
     * @param endColor
     * @param radius
     * @param strokeWidth
     * @param strokeColorString
     * @return
     */

    public static Drawable createLabelBackground(String startColor, String endColor, float radius, int strokeWidth, String strokeColorString) {
        int[] gradientColor = new int[2];
        int strokeColor;
        try {
            gradientColor[0] = Color.parseColor(startColor);
            gradientColor[1] = Color.parseColor(endColor);
        } catch (Exception e) {
            gradientColor[0] = Color.parseColor("#D928D2D1");
            gradientColor[1] = Color.parseColor("#D92F9AF8");
        }
        try {
            strokeColor = Color.parseColor(strokeColorString);
        } catch (Exception e) {
            strokeColor = Color.parseColor("#FF2BE0FF");
        }

        GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, gradientColor);
        gradientDrawable.setShape(GradientDrawable.RECTANGLE);
        gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
        gradientDrawable.setCornerRadius(radius);
        gradientDrawable.setStroke(strokeWidth, strokeColor);
        return gradientDrawable;
    }

    /**
     * @param startColor
     * @param endColor
     * @param radius
     * @param strokeWidth
     * @param strokeColorString
     * @return
     */

    public static Drawable createLabelBackgroundWithAlpha(String startColor, String endColor, float radius, int strokeWidth, String strokeColorString) {
        int[] gradientColor = new int[2];
        int strokeColor;
        try {
            setGradientColor(gradientColor, 0, startColor);
            setGradientColor(gradientColor, 1, endColor);

        } catch (Exception e) {
            gradientColor[0] = ALPHA_COLOR;
            gradientColor[1] = ALPHA_COLOR;
        }
        try {
            if (!TextUtils.isEmpty(strokeColorString)) {
                strokeColor = Color.parseColor(strokeColorString);
            } else {
                strokeColor = ALPHA_COLOR;
            }

        } catch (Exception e) {
            strokeColor = ALPHA_COLOR;
        }

        GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, gradientColor);
        gradientDrawable.setShape(GradientDrawable.RECTANGLE);
        gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
        gradientDrawable.setCornerRadius(radius);
        gradientDrawable.setStroke(strokeWidth, strokeColor);
        return gradientDrawable;
    }

    public static void setGradientColor(int[] gradientColor, int index, String color) {
        if (!TextUtils.isEmpty(color)) {
            gradientColor[index] = Color.parseColor(color);
        } else {
            gradientColor[index] = ALPHA_COLOR;
        }
    }


    public static Bitmap loadBitmapFromView(View v) {
        if (v == null) {
            return null;
        }
        Bitmap screenshot;
        screenshot = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(screenshot);
        canvas.translate(-v.getScrollX(), -v.getScrollY());//我们在用滑动View获得它的Bitmap时候，获得的是整个View的区域（包括隐藏的），如果想得到当前区域，需要重新定位到当前可显示的区域
        v.draw(canvas);// 将 view 画到画布上
        return screenshot;
    }

    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
        try {
            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                    bitmap.getHeight(), Bitmap.Config.ARGB_4444);
            Canvas canvas = new Canvas(output);
            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, bitmap.getWidth(),
                    bitmap.getHeight());
            final RectF rectF = new RectF(new Rect(0, 0, bitmap.getWidth(),
                    bitmap.getHeight()));
            final float roundPx = 14;
            paint.setAntiAlias(true);
            canvas.drawARGB(0, 0, 0, 0);
            paint.setColor(Color.BLACK);
            canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

            final Rect src = new Rect(0, 0, bitmap.getWidth(),
                    bitmap.getHeight());

            canvas.drawBitmap(bitmap, src, rect, paint);
            return output;
        } catch (Exception e) {
            return bitmap;
        }

    }

    public static Bitmap getOvalBitmap(Bitmap bitmap) {

        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                .getHeight(), Bitmap.Config.ARGB_4444);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

        final RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);

        canvas.drawOval(rectF, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }

    private static boolean renameFile(String oldname, String newname) {
        if (!oldname.equals(newname)) {//新的文件名和以前文件名不同时,才有必要进行重命名
            File oldfile = new File(oldname);
            File newfile = new File(newname);
            if (!oldfile.exists()) {
                return false;//文件根本不存在
            }
            if (newfile.exists()) {//若在该目录下已经有一个文件和新文件名相同，则不允许重命名
                newfile.delete();//旧文件需要删除
            }
            return oldfile.renameTo(newfile);
        } else {
            return false;
        }
    }

    private static long getFileSize(String path) {
        if (StringUtils.isTrimEmpty(path)) {
            return -1;
        }

        File file = new File(path);
        return (file.exists() && file.isFile() ? file.length() : -1);
    }

    private static boolean copyFile(String sourceFilePath, String destFilePath) {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(sourceFilePath);
        } catch (FileNotFoundException e) {
            throw new RuntimeException("FileNotFoundException occurred. ", e);
        }
        return writeFile(destFilePath != null ? new File(destFilePath) : null, inputStream, false);
    }

    private static boolean writeFile(File file, InputStream stream, boolean append) {
        OutputStream o = null;
        try {
            makeDirs(file.getAbsolutePath());
            o = new FileOutputStream(file, append);
            byte[] data = new byte[1024];
            int length = -1;
            while ((length = stream.read(data)) != -1) {
                o.write(data, 0, length);
            }
            o.flush();
            return true;
        } catch (FileNotFoundException e) {
            throw new RuntimeException("FileNotFoundException occurred. ", e);
        } catch (IOException e) {
            throw new RuntimeException("IOException occurred. ", e);
        } finally {
            IOUtils.closeQuietly(o);
            IOUtils.closeQuietly(stream);
        }
    }

    private static boolean makeDirs(String filePath) {
        String folderName = getFolderName(filePath);
        if (TextUtils.isEmpty(folderName)) {
            return false;
        }

        File folder = new File(folderName);
        return (folder.exists() && folder.isDirectory()) || folder.mkdirs();
    }

    private static String getFolderName(String filePath) {

        if (TextUtils.isEmpty(filePath)) {
            return filePath;
        }

        int filePosi = filePath.lastIndexOf(File.separator);
        return (filePosi == -1) ? "" : filePath.substring(0, filePosi);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public static Bitmap createVideoThumbnail(String url) {
        Bitmap bitmap = null;
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        int kind = MediaStore.Video.Thumbnails.MINI_KIND;
        try {
            if (Build.VERSION.SDK_INT >= 14) {
                retriever.setDataSource(url, new HashMap<String, String>());
            } else {
                retriever.setDataSource(url);
            }
            bitmap = retriever.getFrameAtTime();
        } catch (IllegalArgumentException ex) {
            // Assume this is a corrupt video file
        } catch (RuntimeException ex) {
            // Assume this is a corrupt video file.
        } finally {
            try {
                retriever.release();
            } catch (RuntimeException ex) {
                // Ignore failures while cleaning up.
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
//        if (kind == MediaStore.Images.Thumbnails.MICRO_KIND && bitmap != null) {
//            bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,
//                    ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
//        }
        return bitmap;
    }
}
